package cn.edu.ptu.jobfairs.services.impl;

import cn.edu.ptu.jobfairs.basic.bo.Interview;
import cn.edu.ptu.jobfairs.basic.bo.InterviewMem;
import cn.edu.ptu.jobfairs.basic.bo.InterviewRes;
import cn.edu.ptu.jobfairs.basic.bo.Resume;
import cn.edu.ptu.jobfairs.basic.common.DataResult;
import cn.edu.ptu.jobfairs.basic.common.ListResult;
import cn.edu.ptu.jobfairs.basic.common.Result;
import cn.edu.ptu.jobfairs.basic.dto.InterviewDTO;
import cn.edu.ptu.jobfairs.basic.dto.request.IdDTO;
import cn.edu.ptu.jobfairs.basic.dto.request.InterviewQueryDTO;
import cn.edu.ptu.jobfairs.core.SqlHandler;
import cn.edu.ptu.jobfairs.core.utils.SqlBuilder;
import cn.edu.ptu.jobfairs.core.utils.UserUtils;
import cn.edu.ptu.jobfairs.core.utils.ValidUtils;
import cn.edu.ptu.jobfairs.services.InterviewService;
import org.apache.catalina.User;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static cn.edu.ptu.jobfairs.basic.common.Errors.INVALID_PARAMS;

/**
 * Created by Lin Chenxiao on 2020-09-10
 **/
@Service
@Transactional
public class InterviewServiceImpl implements InterviewService {

    @Resource
    private SqlHandler sqlHandler;

    @Override
    @PostAuthorize("hasAuthority('hr')")
    public Result addInterview(InterviewDTO interviewDTO) {
        if (ValidUtils.hasBlank(interviewDTO, "id", "handlerId",
                "createTime", "updateTime")) return Result.fail(INVALID_PARAMS);
        interviewDTO.setHandlerId(UserUtils.getId());
        long time = System.currentTimeMillis();
        interviewDTO.setCreateTime(time);
        interviewDTO.setUpdateTime(time);
        Integer id = sqlHandler.create(SqlBuilder.from("insert into # #").append(Interview.class).insert(interviewDTO));
        sqlHandler.insert(SqlBuilder.from("insert into # #").append(InterviewMem.class)
                .insert(interviewDTO.getMembers().stream().map(item -> new InterviewMem(null, id, item))
                        .collect(Collectors.toList())));
        return DataResult.ok(id);
    }

    @Override
    @PostAuthorize("hasAuthority('hr')")
    public Result editInterview(InterviewDTO interviewDTO) {
        if (interviewDTO == null || interviewDTO.getId() == null ||
                CollectionUtils.isEmpty(interviewDTO.getMembers())) return Result.fail(INVALID_PARAMS);
        interviewDTO.setHandlerId(UserUtils.getId());
        interviewDTO.setCreateTime(null);
        interviewDTO.setUpdateTime(System.currentTimeMillis());
        sqlHandler.updateOne(SqlBuilder.from("update # set # where # limit 1").append(Interview.class)
                .update(interviewDTO).where(interviewDTO.getId()));
        sqlHandler.delete(SqlBuilder.from("delete from # where #").append(InterviewMem.class)
                .where("interviewId", interviewDTO.getId()));
        sqlHandler.insert(SqlBuilder.from("insert into # #").append(InterviewMem.class)
                .insert(interviewDTO.getMembers().stream().map(item -> new InterviewMem(null, interviewDTO.getId(), item))
                        .collect(Collectors.toList())));
        return Result.OK;
    }

    @Override
    @PostAuthorize("hasAuthority('hr')")
    public Result delInterview(IdDTO idDTO) {
        if (idDTO == null || idDTO.getId() == null) return Result.fail(INVALID_PARAMS);
        sqlHandler.deleteOne(SqlBuilder.from("delete from # where # and # > #").append(Interview.class)
                .where(idDTO.getId()).columns("arrangedTime").append(System.currentTimeMillis()));
        sqlHandler.delete(SqlBuilder.from("delete from # where #").append(InterviewMem.class)
                .where("interviewId", idDTO.getId()));
        //改变简历状态
        sqlHandler.update(SqlBuilder.from("update # set #=0 where id in (select # from # where #)")
                .append(Resume.class).columns("interviewStatus").columns("resumeId")
                .append(InterviewRes.class).where("interviewId", idDTO.getId()));
        sqlHandler.delete(SqlBuilder.from("delete from # where #").append(InterviewRes.class)
                .where("interviewId", idDTO.getId()));
        return Result.OK;
    }

    @Override
    public Result listInterviews(InterviewQueryDTO interviewQueryDTO) {
        if (interviewQueryDTO == null) return Result.fail(INVALID_PARAMS);
        SqlBuilder sqlBuilder = SqlBuilder.from("select * from #").append(Interview.class);
        if (interviewQueryDTO.getResultType() != null) {
            long time = System.currentTimeMillis();
            sqlBuilder.concat(" where ");
            if (interviewQueryDTO.getResultType() == 0) sqlBuilder
                    .concat("# > # and ").columns("arrangedTime").append(time);
            else if (interviewQueryDTO.getResultType() == 1) sqlBuilder
                    .concat("# < # and ").columns("arrangedTime").append(time);
            SqlBuilder in = SqlBuilder.from("id in (select # from # where #)").columns("interviewId")
                    .append(InterviewMem.class).where("memberId", UserUtils.getId());
            sqlBuilder.concat(in);
        }
        else {
            if (interviewQueryDTO.getMemberId() != null) {
                SqlBuilder in = SqlBuilder.from("id in (select # from # where #)").columns("interviewId")
                        .append(InterviewMem.class).where("memberId", interviewQueryDTO.getMemberId());
                sqlBuilder.and().append(in);
            }
            if (interviewQueryDTO.getArrangedTimeBegin() != null && interviewQueryDTO.getArrangedTimeEnd() != null)
                sqlBuilder.and().between("arrangedTime", interviewQueryDTO.getArrangedTimeBegin(),
                        interviewQueryDTO.getArrangedTimeEnd());
        }
        sqlBuilder.concat(" order by id desc");
        if (interviewQueryDTO.getLimit() != null)
            sqlBuilder.concat(" limit ").concat(interviewQueryDTO.getLimit());
        if (interviewQueryDTO.getOffset() != null)
            sqlBuilder.concat(" offset ").concat(interviewQueryDTO.getOffset());
        List<InterviewDTO> list = sqlHandler.selectAll(sqlBuilder, InterviewDTO.class);
        if (!CollectionUtils.isEmpty(list)) {
            List<InterviewMem> members = sqlHandler.selectAll(SqlBuilder.from("select # from # where #")
                    .columns("interviewId", "memberId").append(InterviewMem.class).in("interviewId", list.stream()
                            .map(InterviewDTO::getId).collect(Collectors.toList())), InterviewMem.class);
            Map<Integer, List<Integer>> map = new HashMap<>();
            for (InterviewMem mem : members) {
                map.computeIfAbsent(mem.getInterviewId(), key -> new LinkedList<>()).add(mem.getMemberId());
            }
            for (InterviewDTO interviewDTO : list) {
                interviewDTO.setMembers(map.get(interviewDTO.getId()));
            }
        }
        return ListResult.ok(list, sqlHandler.count(sqlBuilder.toCount()));
    }
}
